/************************************************************
  Copyright (C), 2004-2018, Sumavision Tech. Co., Ltd.
  FileName: console.c
  Author:   dongjiawei  Date: 2018.01.25    Version: 0.0.1
  Description:this process handle
              1)notification rpc, make sure will notify proper process.
              2)running status, print warning logs and turn on/off warning lights.
  History:
      <author>     <time>       <version >   <desc>
      lixueliang    2018.02.26   0.0.2       Add mechanism of notification dispose
      lixueliang    2018.02.28   0.0.3       Merge Liuzhili code about operation of getting kernel/dtb/software version
      lixueliang    2018.03.06   1.0.0       ADD mechanism of rpc param query.
      lixueliang    2018.08.27   1.0.1       rewrite notify request rpc make up
***********************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <ctype.h>

#include "od_engine.h"
#include "param_msg.h"
#include "message.h"
#include "param_json.h"
#include "other2json.h"

#include "rpc_response.h"
#include "param_save.h"
#include "hard_inf.h"


#include "console_param.h"
#include "sw_monitor.h"

#define DEMO_ARGC 17
#define TASK_HASH_TABLE_SIZE 32

/*default MQ TRANSFER NAME*/
#define DEF_MQ_TRANS_NAME  "tx1_mq_trans"
#define DFT_TRACE_FILE     "trace_console.ini"

extern int32_t console_start(od_framework_t * framework);
extern int32_t console_stop(od_framework_t * framework);

extern void notify_dispose_thread(void *arg);
extern int console_json_param_init(od_framework_t *frameworks, char *filename);
extern void console_json_param_destroy(od_framework_t *frameworks);

typedef struct
{
    uint32_t para_src_id;
    uint32_t dst_id;
    uint32_t sw_monitor_id;
    uint32_t notify_id;
    uint32_t notify_response_id;
    uint32_t param_rpc_id;
    char file_name[OD_MAX_PATH_LEN];
    char post_name[OD_MAX_PATH_LEN];
} console_startup_params;

static int show_help()
{
    fprintf(stdout,
        "console.out:\n"
        "\n"
        "Usage: ./console.out [OPTION]\n"
        "\n"
        "Options:\n"
        "\n"
        "-s,              src od_msg id for send msg\n"
        "-n,              receive od_msg id for notification\n"
        "-d,              dst od_msg id for methodtrans\n"
        "-r,              notify_response id\n"
        "-c,              collect running status rpc id\n"
        "-a,              collect alarm info rpc id\n"
        "-f,              param file name include path\n"
        "-p,              post transfer name"
        "-h,              print this info \n"
        "\n"
        "Examples:\n"
        " ./console.out  -s 10 -n 2 -d 5 -r 7 -c 8 -a 9 -f ./console.json -p tx1_mq_trans\n"
        "\n");
    
    return 0;
}

const char hard_file_name[64] = "/opt/factory/hard.cfg";


static int deal_with_parameter(int argc, char *argv[], console_startup_params *startup_params)
{
    int i;
    
    strncpy(startup_params->post_name, DEF_MQ_TRANS_NAME, OD_MAX_PATH_LEN - 1);
    
    for (i = 1;i < argc;i++)
    {
        if ('-' == argv[i][0])
        {

            if (0 == strcmp(argv[i], "-s") || 0 == strcmp(argv[i], "--src"))
            {
                if (i == argc-1)
                {
                    show_help();
                    return -1;
                }
                i++;
                startup_params->para_src_id = atoi(argv[i]);
            }
            else if (0 == strcmp(argv[i], "-n") || 0 == strcmp(argv[i], "--notify"))
            {
                if (i == argc-1)
                {
                    show_help();
                    return -1;
                }
                i++;
                startup_params->notify_id = atoi(argv[i]);
            }
            else if (0 == strcmp(argv[i], "-d") || 0 == strcmp(argv[i], "--dst"))
            {
                if (i == argc-1)
                {
                    show_help();
                    return -1;
                }
                i++;
                startup_params->dst_id = atoi(argv[i]);
            }
            else if (0 == strcmp(argv[i], "-r") || 0 == strcmp(argv[i], "--rpc"))
            {
                if (i == argc-1)
                {
                    show_help();
                    return -1;
                }
                i++;
                startup_params->notify_response_id = atoi(argv[i]);
            }
            else if (0 == strcmp(argv[i], "-c") || 0 == strcmp(argv[i], "--coll"))
            {
                if (i == argc-1)
                {
                    show_help();
                    return -1;
                }
                i++;
                startup_params->sw_monitor_id = atoi(argv[i]);
            }
            else if (0 == strcmp(argv[i], "-i") || 0 == strcmp(argv[i], "--rpc"))
            {
                if (i == argc-1)
                {
                    show_help();
                    return -1;
                }
                i++;
                startup_params->param_rpc_id = atoi(argv[i]);
            }
            else if (0 == strcmp(argv[i], "-f") || 0 == strcmp(argv[i], "--file"))
            {
                if (i == argc-1)
                {
                    show_help();
                    return -1;
                }
                i++;
                strncpy(startup_params->file_name, argv[i], OD_MAX_PATH_LEN - 1);
            }
            else if (0 == strcmp(argv[i], "-p") || 0 == strcmp(argv[i], "--post"))
            {
                if (i == argc-1)
                {
                    show_help();
                    return -1;
                }
                i++;
                strncpy(startup_params->post_name, argv[i], OD_MAX_PATH_LEN - 1);
            }
            else
            {
                RPTERR("Wrong parameter:%c:%s", argv[i][0], argv[i]);
                show_help();
                return -1;
            }
        }
        else
        {
            show_help();
            RPTERR("Wrong parameter: %s", argv[i]);
            return -1;
        }
    }
    
    if(argc > DEMO_ARGC)
    {
        show_help();
        RPTERR("Wrong parameter nums : %d\n", argc - 1);
        return -1;
    }

    return 0;
}

static response_rpc user_defined_operate(void *handle, jsonrpc_request_t *request)
{
    RPTERR("in user defined operate.");
    return NULL;
}

static void init_param_save_table(param_save_list s_list[], json_param_console *console_handle)
{
    //只需初始化handle和filename，其他在param_save_create时初始化
    s_list[0].save_handle = console_handle->json_hdl;
    s_list[0].save_filename = console_handle->console_json_filename;
}


#define TAB_END {NULL, NULL, NULL}
static rpc_response_tab_desc rpc_response_tab[] = {
    {"console.set", NULL, (void *)rpc_response_default_set},
    {"console.get", NULL, (void *)rpc_response_default_get},
    {"usr.define", NULL, user_defined_operate},
    //{"console.alarm", NULL, (void *)rpc_response_alarm_get},
    TAB_END
};

param_save_list save_tab[] = {
    {NULL, 0, 0, NULL, NULL},
    {NULL, 0, 0, NULL, NULL},
};


static void rpc_response_tab_init(rpc_response_tab_desc rpc_response_tab[],
                                  param_save_list s_list[],
                                  json_param_console *json_param)
{
    s_list[0].save_handle = json_param->json_hdl;
    rpc_response_tab[0].handle = rpc_response_tab[1].handle = &s_list[0];
    rpc_response_tab[2].handle = NULL;//非预设方法
    //rpc_response_tab[3].handle = json_param->alarm_clct_handle;
    return;
}

static od_framework_t* console_params_tab_init(console_startup_params startup_params)
{
    od_framework_t * frameworks;
    json_param_console *json_param;
    /*create framework*/
    frameworks = od_framework_create(sizeof(json_param_console), TASK_HASH_TABLE_SIZE);
    json_param = frameworks->param_table;
    if(NULL == json_param)
    {
       RPTERR("param_table alloc error");
       return NULL; 
    }

    /*参数表初始化*/
    if(console_json_param_init(frameworks, startup_params.file_name) < 0)
    {
        RPTERR("json_param init error");
        return NULL; 
    }

    /*param_rpc_handle get info in sw and alarm*/
    json_param->rpc_handle = param_rpc_create(startup_params.post_name, startup_params.param_rpc_id, startup_params.dst_id, 1000);
    if( NULL == json_param->rpc_handle )
    {
        RPTERR("rpc_handle create error");
        return NULL;
    }

    strncpy(json_param->post_name, startup_params.post_name, OD_MAX_PATH_LEN - 1);
    json_param->sw_monitor_id = startup_params.sw_monitor_id;
    json_param->dst_id = startup_params.dst_id;
    json_param->notify_id = startup_params.notify_id;

    return frameworks;
}

static rpc_response_task_handle params_rpc_response_task_start(json_param_console *json_param,
                                                               console_startup_params startup_params)
{
    rpc_response_task_handle rpc_response_hdl = NULL;
    rpc_response_static_params_t rpc_response_statics = glb_rpc_response_static_params_default;

    /*启动参数接收处理任务，可与其他任务交互*/
    rpc_response_tab_init(rpc_response_tab, save_tab, json_param);

    rpc_response_statics.msg_local_id = startup_params.para_src_id;
    rpc_response_statics.table = rpc_response_tab;
    strncpy(rpc_response_statics.post_name, startup_params.post_name, OD_MAX_OBJ_NAME - 1);
    rpc_response_hdl = rpc_response_create(&rpc_response_statics, NULL);
    od_task_start(rpc_response_hdl, 60);

    return rpc_response_hdl;
}

mq_trans_handle cpu_trans_create(char *trans_name)
{
    mq_trans_handle t_trans;
    mq_trans_static_params static_param;

    memset(&static_param, 0, sizeof(mq_trans_static_params));
    static_param.no_block_flg_to_send = 1;
    static_param.name_len = sprintf(static_param.name, "%s", trans_name);

    t_trans = mq_trans_create(&static_param, NULL);
    if(NULL == t_trans)
    {
        printf(" mq_trans_create error");
        return NULL;
    }

    od_task_start(t_trans, 50);

    return t_trans;
}

/*initialize the running environment*/
static void env_init()
{
   od_init();
   odin_trace_init(NULL, DFT_TRACE_FILE);
}

/*发送一个网络通知，设置mac*/
static void set_mac_msg(void * hdl,  int net_id, char* mac)
{
    json_param_console * json_param = hdl;
    char param_name[OD_MAX_PATH_LEN];
    int ret = 0;

    snprintf(param_name, OD_MAX_PATH_LEN - 1, "network.net[%d].mac", net_id);

    ret = set_params_by_mq( json_param->rpc_handle, param_name, PT_STRI_, mac);
    if(OD_OK == ret)
    {
        RPTWRN("set net[%d] mac %s", net_id, mac );
    }

    return;
}

static void read_hd_inf(const char * filename, json_param_console *json_param)
{
    int ret = 0;
    hard_information_t hard_inf;
    char *odin_ver = NULL;
    console_param * params = &(json_param->mem);

    memset(&hard_inf, -1, sizeof(hard_inf));
    ret = read_hard_inf(filename, &hard_inf);
    if (OD_OK == ret)
    {
        /*success*/
        strncpy(params->sys.hard_ver, hard_inf.hard_ver, OD_MAX_OBJ_NAME - 1);
        strncpy(params->sys.sn, hard_inf.sn, OD_MAX_OBJ_NAME - 1);
        strncpy(params->sys.mac0, hard_inf.mac1, OD_MAX_OBJ_NAME - 1);
        strncpy(params->sys.mac1, hard_inf.mac2, OD_MAX_OBJ_NAME - 1);

        /*set mac addr notify to network.out*/
        set_mac_msg(json_param, 0, params->sys.mac0);
        set_mac_msg(json_param, 1, params->sys.mac1);
    }
    else
    {
        /*do nothing*/
    }

    /*载入odin的版本*/
    odin_ver = od_engine_get_ver();
    strncpy(params->sys.odin_ver, odin_ver, OD_MAX_OBJ_NAME - 1);
}

static void runtime_get(console_param * params)
{
    uint32_t  tm;
    int sec;
    int min;
    int hour;

    tm = od_uptime_sec();

    sec = tm % 60;
    tm /= 60;
    min = tm % 60;
    tm /= 60;
    hour = tm;

    memset(params->sys.runtime, 0, OD_MAX_OBJ_NAME);
    sprintf(params->sys.runtime, "%u hours %u min %u sec", hour,min,sec);
}

int main(int argc, char *argv[])
{
    mq_trans_handle t_trans = NULL;
    console_startup_params startup_params;
    param_save_static_params_t param_save_statics = glb_param_save_static_params_default;
    param_save_handle param_save_hdl = NULL;
    rpc_response_task_handle rpc_response_hdl = NULL;
    OD_THREAD_ID notify_dispose_thread_id;
    od_framework_t *frameworks = NULL;
    json_param_console *json_param = NULL;
    notify_params  notify_inti_params;
    uint32_t nums = 0;

    env_init();

    memset(&startup_params, 0, sizeof(console_startup_params));
    if(deal_with_parameter(argc, argv, &startup_params) != 0)
    {
       return OD_ERROR;
    }

    t_trans = cpu_trans_create(startup_params.post_name);

    frameworks = console_params_tab_init(startup_params);
    if(frameworks == NULL)
    {
        return OD_ERROR;
    }
    json_param = frameworks->param_table;

    /*启动需要启动的线程任务*/
    console_start(frameworks);

    /*初始化和启动参数保存线程*/
    param_save_statics.list_num = sizeof(save_tab)/sizeof(param_save_list);
    init_param_save_table(save_tab, (json_param_console *)json_param);
    param_save_statics.s_list = save_tab;
    param_save_statics.save_func = NULL;
    param_save_hdl = param_save_create(&param_save_statics, NULL);
    od_task_start(param_save_hdl, 60);

    /*读取硬件信息*/
    read_hd_inf(hard_file_name, json_param);

    rpc_response_hdl = params_rpc_response_task_start(json_param, startup_params);

    strncpy( notify_inti_params.post_name, startup_params.post_name, OD_MAX_PATH_LEN - 1);
    notify_inti_params.notify_id = startup_params.notify_id;
    notify_inti_params.notify_response_id = startup_params.notify_response_id;
    notify_inti_params.dst_id = startup_params.dst_id;

    notify_dispose_thread_id = od_thread_create("notify_dispose", 99, 0x1000000, notify_dispose_thread, &notify_inti_params);
    
    while(1)
    {
        od_msleep(2000);
        runtime_get(&(json_param->mem));
        nums++;
        if((nums & 0x1f) == 0x1f)
        {
            /*print per 32 times*/
            OD_PRINT("runtime: %s\n",json_param->mem.sys.runtime);
        }
    }

    od_thread_join(notify_dispose_thread_id);

    od_task_stop(param_save_hdl);
    od_task_delete(param_save_hdl);

    od_task_stop(rpc_response_hdl);
    od_task_delete(rpc_response_hdl);

    od_task_stop(t_trans);

    /*终止已启动的线程任务*/
    console_stop(frameworks);

    /*退出*/
    console_json_param_destroy(frameworks);

    od_framework_destroy(frameworks);

    odin_trace_exit();
    return OD_OK;
}

